import {
  BadRequestException,
  Body,
  Controller,
  DefaultValuePipe,
  Get,
  Headers,
  Inject,
  Logger,
  Param,
  ParseEnumPipe,
  ParseIntPipe,
  Post,
  Query,
  Res,
  Session,
  StreamableFile,
  UnauthorizedException,
  UploadedFile,
  UploadedFiles,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';
import { AppService } from './app.service';
import { TestCustomDecorator } from './TestCustomDecorator';
import { TestGuard } from './TestGuard';
import { Ddd, MergeTest, TestMergeDecorator } from './TestMergeDecorator';
import { FileInterceptor, FilesInterceptor } from '@nestjs/platform-express';
import * as fs from 'fs';
import { WINSTON_LOGGER_TOKEN } from './winston/winston.module';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { Response } from 'express';
import { MINIO_CLIENT } from './minio/minio.module';
import * as sharp from 'sharp';
import { ClientGrpc, ClientProxy } from '@nestjs/microservices';
import { Etcd3 } from 'etcd3';
import { DepartmentService } from './department.service';
import { EmployeeService } from './employee.service';
const OSS = require('ali-oss');
const path = require('path');
const mysql = require('mysql2');
const Minio = require('minio');

enum Ggg {
  AAA = '111',
  BBB = '222',
  CCC = '333',
}

interface FindById {
  id: number;
}
interface Book {
  id: number;
  name: string;
  desc: string;  
}
interface BookService {
  findBook(param: FindById): Book 
}
// @Controller()
// @Ddd()
@MergeTest('', 'is good')
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Inject(JwtService)
  private jwtService: JwtService;

  @Inject(ConfigService)
  private configService: ConfigService;

  @Inject(WINSTON_LOGGER_TOKEN)
  private logger;

  // @Get()
  // @UseGuards(TestGuard)
  // async getHello() {
  //   this.logger.warn('abin', AppController.name);
  //   return this.appService.getHello();
  // }

  // 自定义装饰器
  @Get('decorator')
  @TestCustomDecorator('admin')
  @UseGuards(TestGuard)
  testCustomDecorator() {
    return 'test cutsom decorator';
  }

  // 合并装饰器
  @Get('merge')
  testMergeDecorator(@TestMergeDecorator('accept') c) {
    return c;
  }

  // 内置pipe
  @Get('internalEnum/:enum')
  testInternalPipe(@Param('enum', new ParseEnumPipe(Ggg)) e: Ggg) {
    return e;
  }

  @Get('internalEnum')
  testInternalPipe2(@Query('kkk', new DefaultValuePipe('aaa')) kkk: string) {
    return kkk;
  }

  // 用multer实现上传
  @Post('upload')
  // @UseInterceptors(FileInterceptor('aaa', {
  //   dest: 'uploads'
  // }))
  testUploadByMulter(@UploadedFile() file: Express.Multer.File, @Body() body) {
    console.log('body', body);
    console.log('file', file);
  }

  // 用multer实现上传
  @Post('uploads')
  // @UseInterceptors(FileInterceptor('aaa', {
  //   dest: 'uploads'
  // }))
  @UseInterceptors(
    FilesInterceptor('bbb', 3, {
      dest: 'uploads',
    }),
  )
  testUploadByMulter2(
    @UploadedFiles() files: Array<Express.Multer.File>,
    @Body() body,
  ) {
    console.log('body', body);
    console.log('files', files);
  }

  // 用multer实现上传,key, val
  @Post('uploads')
  // @UseInterceptors(FileInterceptor('aaa', {
  //   dest: 'uploads'
  // }))
  @UseInterceptors(
    FilesInterceptor('bbb', 3, {
      dest: 'uploads',
    }),
  )
  testUploadByMulter3(
    @UploadedFiles() files: Array<Express.Multer.File>,
    @Body() body,
  ) {
    console.log('body', body);
    console.log('files', files);
  }

  @Post('testuploadgif')
  @UseInterceptors(
    FileInterceptor('file', {
      dest: 'uploads',
    }),
  )
  async testuploadgif(@UploadedFile() file: Express.Multer.File) {
    console.log(file);
    return file.path;
  }

  @Get('compression')
  async compression(
    @Query('path') filePath: string,
    @Query('color', ParseIntPipe) color: number,
    @Res() res: Response,
  ) {
    console.log(filePath, color);
    if (!fs.existsSync(filePath)) {
      throw new BadRequestException('文件不存在');
    }

    const data = await sharp(filePath, {
      animated: true,
      limitInputPixels: false,
    }).toBuffer();
    res.set('Content-Disposition', `attachment; filename="dest.gif"`);
    res.send(data);
  }

  @Post('bigUploads')
  @UseInterceptors(
    FilesInterceptor('files', 20, {
      dest: 'uploads',
    }),
  )
  testBigUpload(
    @UploadedFiles() files: Array<Express.Multer.File>,
    @Body() body,
  ) {
    console.log('body', body);
    console.log('files', files);
    const fileName = body.name.match(/(.+)\-\d+$/)[1];
    const chunkDir = 'uploads/chunks_' + fileName;
    if (!fs.existsSync(chunkDir)) {
      fs.mkdirSync(chunkDir);
    }
    fs.cpSync(files[0].path, chunkDir + '/' + body.name);
    fs.rmSync(files[0].path);
  }

  @Get('mergeFile')
  merge(@Query('name') name: string) {
    const chunkDir = 'uploads/chunks_' + name;
    const files = fs.readdirSync(chunkDir);
    let count = 0;
    let startPos = 0;
    files.map((file) => {
      const filePath = chunkDir + '/' + file;
      const stream = fs.createReadStream(filePath);
      stream
        .pipe(
          fs.createWriteStream('uploads/' + name, {
            start: startPos,
          }),
        )
        .on('finish', () => {
          count++;
          if (count === files.length) {
            fs.rm(chunkDir, { recursive: true }, () => {});
          }
        });

      startPos += fs.statSync(filePath).size;
    });
  }

  @Get('oss')
  testoss() {
    const client = new OSS({
      // yourregion填写Bucket所在地域。以华东1（杭州）为例，Region填写为oss-cn-hangzhou。
      region: 'oss-cn-beijing',
      // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
      accessKeyId: 'LTAI5tDockwd59MucH7TYB1b',
      accessKeySecret: 'o1qUaucDqn311MT5vcj3ZfXz0hiTZQ',
      // 填写Bucket名称。
      bucket: 'abin-1',
    });

    async function put() {
      try {
        // 填写OSS文件完整路径和本地文件的完整路径。OSS文件完整路径中不能包含Bucket名称。
        // 如果本地文件的完整路径中未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。
        const result = await client.put(
          '1.jpg',
          path.normalize(
            '/Users/abin/learn/nest-learn/uploads/403953_461724913838_.pic.jpg',
          ),
        );
        console.log(result);
      } catch (e) {
        console.log(e);
      }
    }

    put();
  }

  @Get('oss2')
  async testoss2() {
    const config = {
      // yourregion填写Bucket所在地域。以华东1（杭州）为例，Region填写为oss-cn-hangzhou。
      region: 'oss-cn-beijing',
      // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
      accessKeyId: 'LTAI5tDockwd59MucH7TYB1b',
      accessKeySecret: 'o1qUaucDqn311MT5vcj3ZfXz0hiTZQ',
      // 填写Bucket名称。
      bucket: 'abin-1',
    };
    const client = new OSS(config);

    const date = new Date();

    date.setDate(date.getDate() + 1);
    const res = client.calculatePostSignature({
      expiration: date.toISOString(),
      conditions: [
        ['content-length-range', 0, 1048576000], //设置上传文件的大小限制。
      ],
    });
    console.log(res);

    const location = await client.getBucketLocation();

    const host = `http://${config.bucket}.${location.location}.aliyuncs.com`;

    console.log(host);
  }

  @Get('testminio')
  async testMinio() {
    var minioClient = new Minio.Client({
      endPoint: 'localhost',
      port: 9000,
      useSSL: false,
      accessKey: 'GWCuYxY8s83nnaMg0OS9',
      secretKey: 'KZeknlNxlmqqeSTZDx3dI2yIpaViCetWEXrkY21A',
    });

    function put() {
      minioClient.fPutObject(
        'aaa',
        'hello.jpg',
        path.normalize(
          '/Users/abin/learn/nest-learn/uploads/403953_461724913838_.pic.jpg',
        ),
        function (err, etag) {
          if (err) return console.log(err);
          console.log('上传成功');
        },
      );
    }

    put();
  }

  @Get('testminio2')
  async testMinio2() {
    var minioClient = new Minio.Client({
      endPoint: 'localhost',
      port: 9000,
      useSSL: false,
      accessKey: 'GWCuYxY8s83nnaMg0OS9',
      secretKey: 'KZeknlNxlmqqeSTZDx3dI2yIpaViCetWEXrkY21A',
    });

    function get() {
      minioClient.getObject('aaa', 'hello.jpg', function (err, stream) {
        if (err) return console.log(err);
        stream.pipe(fs.createWriteStream('./abin.jpg'));
      });
    }

    get();
  }

  @Get('testminio3')
  async testMinio3() {}

  @Get('getconfig')
  async testGetConfig() {
    return {
      // aaa: this.configService.get('mysql_server_host'),
      db: this.configService.get('db'),
      config: this.configService.get('aaa.bbb.ccc'),
    };
  }

  @Get('sss')
  async testSession(@Session() session) {
    console.log(session);
    session.count = session.count ? session.count + 1 : 1;
    return session.count;
  }

  @Get('testjwt')
  async testjwt(
    @Headers('authorization') authorization: string,
    @Res({ passthrough: true }) response: Response,
  ) {
    if (authorization) {
      try {
        const token = authorization.split(' ')[1];
        const data = this.jwtService.verify(token);
        const newToken = this.jwtService.sign({
          count: data.count + 1,
        });
        response.setHeader('token', newToken);
        return data.count + 1;
      } catch (e) {
        console.log(e);
        throw new UnauthorizedException();
      }
    } else {
      const newToken = this.jwtService.sign({
        count: 1,
      });
      response.setHeader('token', newToken);
      return 1;
    }
  }

  @Get('download')
  download(@Res() res: Response) {
    const content = fs.readFileSync('package.json');
    res.set('Content-Disposition', `attachment; filename="abin.json"`);
    res.end(content);
  }
  @Get('download2')
  download2() {
    const stream = fs.createReadStream('package.json');
    return new StreamableFile(stream, {
      type: 'text/plain',
      disposition: `attachment; filename="package.json"`,
    });
  }
  @Get('download3')
  download3() {
    const stream = fs.createReadStream('package.json');

    return new StreamableFile(stream, {
      type: 'text/plain',
      disposition: `attachment; filename="package.json"`,
    });
  }

  @Get('testi18n')
  getI18n() {
    return this.appService.testI18n();
  }

  @Post('log')
  log(@Body() log) {
    console.log('log', log);
  }
  @Inject('USER_SERVICE')
  private userClient: ClientProxy;

  @Get('sum')
  calc(@Query('num') str) {
    const numArr = str.split(',').map((item) => parseInt(item));

    this.userClient.emit('log', '求和')
    return this.userClient.send('sum', numArr);
  }

  @Inject('BOOK_PACKAGE')
  private client: ClientGrpc

  private bookService: BookService

  onModuleInit() {
    this.bookService = this.client.getService('BookService');
  }

  @Get('book/:id')
  getHero(@Param('id') id: number) {
    return this.bookService.findBook({
      id
    })
  }

  
  
   
  @Inject('ETCD_CLIENT')
  private etcdClient: Etcd3

  @Get('put')
  async put(@Query('value') value: string) {
    await this.etcdClient.put('aaa').value(value)
    return 'done'
  }

  @Get('get')
  async get() {
    return await this.etcdClient.get('aaa').string()
  }

  @Get('del')
  async del() {
    await this.etcdClient.delete().key('aaa')
    return 'done'
  }

  @Inject(DepartmentService)
  private departmentService: DepartmentService

  @Inject(EmployeeService)
  private employeeService: EmployeeService

  @Get('createPrisma')
  async create() {
    const department = await this.departmentService.create({
      name: '技术部2'
    });

    await this.employeeService.create({
      name: '张三2',
      phone: '13222222222',
      department: {
        connect: {
          id: department.id
        }
      }
    });

    return 'done';
  }
}
